package com.example.permission.config;

import com.example.permission.annotation.ApiPermission;
import com.example.permission.entity.ApiResource;
import com.example.permission.repository.ApiResourceRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Component
public class ApiPermissionScanner implements ApplicationRunner {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ApiResourceRepository apiResourceRepository;

    @Override
    public void run(org.springframework.boot.ApplicationArguments args) {
        Map<String, Object> beans = applicationContext.getBeansWithAnnotation(RestController.class);

        for (Object bean : beans.values()) {
            // 获取原始类（去掉 CGLIB 代理包装）
            Class<?> targetClass = ClassUtils.getUserClass(bean);
            String basePath = getBasePath(targetClass);

            for (Method method : targetClass.getDeclaredMethods()) {
                ApiPermission api = method.getAnnotation(ApiPermission.class);
                if (api == null) continue;

                String methodPath = getMethodPath(method);
                String httpMethod = getHttpMethod(method);

                String fullPath = normalizePath(basePath + methodPath);
                String code = (api.code().isEmpty()) ? fullPath : api.code();

                String permissions = Arrays.stream(api.permissions())
                    .map(Enum::name)
                    .collect(Collectors.joining(","));

                Optional<ApiResource> existing = apiResourceRepository.findByCode(code);
                if (existing.isPresent()) {
                    continue;
                }

                ApiResource resource = new ApiResource();
                resource.setName(api.name());
                resource.setCode(code);
                resource.setUri(fullPath);
                resource.setMethod(httpMethod);
                resource.setPermissions(permissions);
                apiResourceRepository.save(resource);

                log.info("✅ 注册接口权限: [{} {}] -> code={}, permissions={}", httpMethod, fullPath, code, permissions);
            }
        }
    }

    private String getBasePath(Class<?> clazz) {
        RequestMapping mapping = clazz.getAnnotation(RequestMapping.class);
        if (mapping != null && mapping.value().length > 0) {
            return mapping.value()[0];
        }
        return "";
    }

    private String getMethodPath(Method method) {
        if (method.isAnnotationPresent(GetMapping.class)) {
            return method.getAnnotation(GetMapping.class).value()[0];
        }
        if (method.isAnnotationPresent(PostMapping.class)) {
            return method.getAnnotation(PostMapping.class).value()[0];
        }
        if (method.isAnnotationPresent(PutMapping.class)) {
            return method.getAnnotation(PutMapping.class).value()[0];
        }
        if (method.isAnnotationPresent(DeleteMapping.class)) {
            return method.getAnnotation(DeleteMapping.class).value()[0];
        }
        if (method.isAnnotationPresent(RequestMapping.class)) {
            return method.getAnnotation(RequestMapping.class).value()[0];
        }
        return "";
    }

    private String getHttpMethod(Method method) {
        if (method.isAnnotationPresent(GetMapping.class)) return "GET";
        if (method.isAnnotationPresent(PostMapping.class)) return "POST";
        if (method.isAnnotationPresent(PutMapping.class)) return "PUT";
        if (method.isAnnotationPresent(DeleteMapping.class)) return "DELETE";
        RequestMapping rm = method.getAnnotation(RequestMapping.class);
        return (rm != null && rm.method().length > 0) ? rm.method()[0].name() : "GET";
    }

    private String normalizePath(String path) {
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        return path.replaceAll("//+", "/"); // 去重双斜杠
    }
}
